<?php

class Common_SSH2 extends ClassStructure_Mixin_Delegator
{

    private $isConnected = false;
    private $host = null;

    public function __construct($host, array $options = array())
    {
        parent::__construct();

        if (empty($host) || !is_string($host)) {
            throw new Common_Exception('The host supplied [' . $host . '] must be a non-empty string.');
        }

        $this->host = $host;
        
        if (isset($options['host'])) {
            unset($options['host']);
        }

        $mixin = new ClassStructure_Mixin_Property($options);
        $this->__addMixin($mixin, 'property');

        $mixin = new Common_Mixin_Logger();
        $this->__addMixin($mixin, 'log');
    }

    public function getHost()
    {
        return $this->host;
    }
    
    public function connect()
    {
        $this->isConnected = true;
        return $this;
    }

    public function isConnected()
    {
        return ($this->isConnected === true);
    }

    public function exec($command)
    {
        
        $returnValue = false;

        try {

            if ($this->isConnected()) {

                $options = array();

                $identityFile = $this->getProperty('identity', null);
                if (!empty($identityFile)) {
                    $options[] = '-i ' . $identityFile;
                }

                $options = implode(' ', $options);
                if (!empty($options)) {
                    $options = ' ' . $options;
                }

                $sshCommand = 'ssh' . $options . ' ' . $this->host . ' "' . $command . '"';

                $this->log($sshCommand, Zend_Log::DEBUG);

                $output = array();
                $return = null;
                exec($sshCommand, $output, $return);

                if ($return != 0) {
                    
                    $this->log('Error: The command [' . $command . '] returned with a non-zero exit code [' . $return . '].', Zend_Log::ERR);

                    foreach ($output as $line) {
                        $this->log('  > ' . $line, Zend_Log::DEBUG);
                    }

                    throw new Common_Exception('Error with preceeding SSH-CLI command.', Zend_Log::ERR);
                    
                }

                $returnValue = $output;

            }

        } catch (Exception $exception) {
            $this->log('Exception occurred while executing ssh command [' . $sshCommand . ']: ' . $exception->getMessage());
            throw $exception;
        }

        return $returnValue;

    }

    public function moveFile($source, $destination, $useSudo = null)
    {
        if (
            !empty($source) && is_string($source) &&
            !empty($destination) && is_string($destination)
        ) {

            $sudoAccess = '';
            if ($useSudo === true) {
                $sudoAccess = 'sudo ';
            }

            $this->exec($sudoAccess . 'mv ' . $source . ' ' . $destination);
        }
    }

    public function uploadFile($localSource, $remoteTargetPath)
    {
        try {

            if ($this->isConnected()) {

                $options = array();

                $options = implode(' ', $options);
                if (!empty($options)) {
                    $options = ' ' . $options;
                }
                
                $targetUrl = $this->getScpUrl() . ':' . $remoteTargetPath;

                $scpCommand = 'scp' . $options . ' ' .$localSource . ' ' . $targetUrl;

                $this->log($scpCommand, Zend_Log::DEBUG);

                $output = array();
                $return = null;
                exec($scpCommand, $output, $return);

                $returnValue = $output;

            }

        } catch (Exception $exception) {
            $this->log('Exception occurred while executing ssh command [' . $scpCommand . ']: ' . $exception->getMessage());
        }
    }

    protected function getScpUrl()
    {

        $user = $this->getProperty('user', null);
        $host = $this->getHost();

        $url = $user . '@' . $host;

        return $url;
    }

    public function setLogger(Zend_Log $obj_logger)
    {
        $this->__addMixin($obj_logger, 'log');
    }

    public function getLogger()
    {
        return $this->__getMixin('log');
    }

    public function hasLogger()
    {
        return $this->__hasMixin('log');
    }

    protected function log($str_message, $enm_priority = Zend_Log::INFO)
    {
        if($this->hasLogger()) {
            $this->__getMixin('log')->log($str_message, $enm_priority);
        }
    }

}
